package com.yuhuihui.common.utils.mail;

import com.yuhuihui.common.utils.ThreadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.util.ObjectUtils;

import jakarta.mail.internet.MimeMessage;
import java.util.Properties;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 邮箱工具类
 *
 * @author yuhh
 * @date 2023-05-25 14:00:05
 */
public class MailUtil {

    private static final Logger logger = LoggerFactory.getLogger(MailUtil.class);

    /**
     * 邮件发送器
     */
    private static final JavaMailSenderImpl MAIL_SENDER = createMailSender();

    /**
     * 邮件线程名
     */
    private static final String MAIL_THREAD_NAME = "mailThread";

    public static String EMAIL = MailConfig.SEND_EMAIL;

    /**
     * 发送邮件--以html格式
     *
     * @param to      接受人，多个以","分割
     * @param subject 主题
     * @param html    发送内容(html代码)
     * @author yuhh
     * @date 2023-05-25 14:00:16
     */
    public static void sendMailForHtml(String to, String subject, String html) {
       sendMailForHtmlHaveAttachment(to, subject, html, null, null);
    }

    /**
     * 发送邮件--普通文本
     *
     * @param to      接受人，多个以","分割
     * @param subject 主题
     * @param text    发送内容
     * @author yuhh
     * @date 2023-05-25 14:00:19
     */
    public static void sendMailBasic(String to, String subject, String text) {
        sendMail(to, subject, text, false, null, null);
    }

    /**
     * 发送邮件--以html格式，带附件
     *
     * @param to                接受人，多个以","分割
     * @param subject           主题
     * @param html              发送内容(html代码)
     * @param suffixName        附件后缀名
     * @param inputStreamSource 文件inputStreamSource
     * @author yuhh
     * @date 2023-05-25 14:00:40
     */
    public static void sendMailForHtmlHaveAttachment(String to, String subject, String html, String suffixName, InputStreamSource inputStreamSource) {
        sendMail(to, subject, html, true, suffixName, inputStreamSource);
    }

    /**
     * 发送邮件
     *
     * @param to                接受人，多个以","分割
     * @param subject           主题
     * @param test              发送内容
     * @param isHtml            发送内容是否是html代码
     * @param suffixName        附件后缀名
     * @param inputStreamSource 文件inputStreamSource
     * @author yuhh
     * @date 2023-05-25 14:00:43
     */
    private static void sendMail(String to, String subject, String test,  boolean isHtml,
                                 String suffixName, InputStreamSource inputStreamSource){
        if (!MailConfig.IS_SEND){
            logger.info("配置无需发送邮件");
            return;
        }
        if (ObjectUtils.isEmpty(to)){
            logger.info("无收件人需要发送");
            return;
        }
        MimeMessage mimeMessage = MAIL_SENDER.createMimeMessage();
        MimeMessageHelper messageHelper = getMessageHelper(mimeMessage, subject, test, isHtml, suffixName, inputStreamSource);
        ThreadPoolExecutor executor = ThreadUtil.buildThreadPool(1, MAIL_THREAD_NAME);
        executor.execute(new SendMailThread(messageHelper, mimeMessage, to));
    }

    /**
     * 获取邮件内容
     *
     * @param mimeMessage       邮件发送器信息
     * @param subject           主题
     * @param test              发送内容
     * @param isHtml            发送内容是否是html代码
     * @param suffixName        附件后缀名
     * @param inputStreamSource 文件inputStreamSource
     * @return {@link MimeMessageHelper }
     * @author yuhh
     * @date 2023-05-25 14:00:47
     */
    private static MimeMessageHelper getMessageHelper(MimeMessage mimeMessage, String subject, String test, boolean isHtml,
                                                      String suffixName, InputStreamSource inputStreamSource) {
        try {
            // 设置utf-8或GBK编码，否则邮件会有乱码
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
            messageHelper.setFrom(MailConfig.MAIL_EMAIL_FROM, MailConfig.MAIL_PERSONAL);
            messageHelper.setSubject(subject);
            messageHelper.setText(test, isHtml);
            if (inputStreamSource != null) {
                messageHelper.addAttachment(subject + suffixName, inputStreamSource);
            }
            return messageHelper;
        } catch (Exception e) {
            logger.error("构建邮件内容出现异常", e);
        }
        return null;
    }

    /**
     * 发送邮件线程类
     * @author yuhh
     * @date 2019/11/28 15:34
     */
    private static class SendMailThread implements Runnable{

        /**
         * 邮件内容
         */
        private final MimeMessageHelper messageHelper;
        /**
         * 邮件发送器
         */
        private final MimeMessage mimeMessage;
        /**
         * 接受人，多个以","分割
         */
        private final String to;

        private SendMailThread(MimeMessageHelper messageHelper, MimeMessage mimeMessage, String to){
            this.messageHelper = messageHelper;
            this.mimeMessage = mimeMessage;
            this.to = to;
        }

        @Override
        public void run() {
            try{
                messageHelper.setTo(to.split(","));
                MAIL_SENDER.send(mimeMessage);
            } catch (Exception e) {
                logger.error("发送给‘{}’的邮件异常", to, e);
            }
        }
    }

    /**
     * 建立邮件发送器
     *
     * @return {@link JavaMailSenderImpl }
     * @author yuhh
     * @date 2023-05-25 14:00:55
     */
    private static JavaMailSenderImpl createMailSender() {
        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        sender.setHost(MailConfig.MAIL_HOST);
        sender.setPort(MailConfig.MAIL_PORT);
        sender.setUsername(MailConfig.MAIL_USER_NAME);
        sender.setPassword(MailConfig.MAIL_PASSWORD);
        sender.setDefaultEncoding("Utf-8");
        Properties p = new Properties();
        p.setProperty("mail.smtp.timeout", MailConfig.MAIL_TIMEOUT);
        p.setProperty("mail.smtp.auth", "true");
        p.setProperty("mail.smtp.ssl.enable", "true");
        p.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        sender.setJavaMailProperties(p);
        return sender;
    }
}
